home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac-Source 1994 July
/
Mac-Source_July_1994.iso
/
C and C++
/
System
/
HyperSimple
/
HyperSimple.c
next >
Wrap
Text File
|
1990-12-22
|
17KB
|
727 lines
/****************************************************************
*
* HyperSimple.c
*
* Simple XCmd for Hypercard 2.0 that demonstrates the use
* of the external windows extensions. This will compile
* with MPW or THINK (at least 4.0.4).
*
* These calls are actually fairly easy to use. There are,
* naturally, some holes in the documentation. For instance,
* while you as the XCMD writer *do* own the window's refCon,
* you *do not* own the windowKind field, which is used by
* Hypercard to keep track of the windows.
*
* Here's the MPW build stuff:
HyperSimple ƒƒ HyperSimple.c.o HyperXLib.o
Link -w -t rsrc -c RSED -rt XCMD=1000 -m MAIN -sg HyperSimple -sym on -mf ∂
HyperSimple.c.o HyperXLib.o ∂
"{CLibraries}"StdClib.o ∂
"{CLibraries}"CInterface.o ∂
"{CLibraries}"CRuntime.o ∂
"{Libraries}"Interface.o ∂
-o HyperSimple
HyperSimple.c.o ƒ HyperSimple.c
C -sym on -b -r HyperSimple.c
* The THINK C project format is:
*
* Name: HyperSimple
* Type: XCMD
* ID: 1000
* Attrs: 20 (purgeable)
*
* Use <MacHeaders>
*
* Libraries included:
* MacTraps
* HyperXLib.π
* ANSI-A4 (for strlen)
*
* This is sample code, so I hope that you learn from it.
* Please note, however, that it is:
*
* Copyright © 1990 Bill Hofmann, All rights reserved
*
* Any comments or questions are welcome, and can be addressed to:
*
* Bill Hofmann
* PO Box 460904
* San Francisco CA 94146
*
* Internet: wdh@well.sf.ca.us
* AppleLink: D6082
*
* Enjoy!
*
* Edit history
*
* 10/30/90 wdh created
* 12/22/90 wdh revised and documented
*
****************************************************************/
#include "MPWandTHINK.h"
#ifdef THINK_C
#include <string.h>
#else /* MPW */
#include <Memory.h>
#include <ToolUtils.h>
#include <String.h>
#endif THINK_C
#include "HyperXCmd.h"
#ifndef NIL
#define NIL ((void *) 0)
#endif NIL
/****************************************************************/
/******** Defines *********/
/****************************************************************/
#define msgUsage "HyperSimple <title> [, <bounds rect> ]]"
#define msgVersion "HyperSimple v1.0 12/22/90 © Bill Hofmann"
#define msgBadDiameter "Error: Diameter must be greater than zero."
#define msgBadWindowSize "Error: New window size must be greater than \"32, 32\"."
#define msgParmErr "Parameter error."
#define supportedProperties \
"loc, visible, properties, diameter, size"
#define strDefaultTitle "\pUntitled"
#define kDefaultDiameter 20
/****************************************************************/
/******** typedefs *********/
/****************************************************************/
typedef struct {
Point center;
long color;
} windoid_object;
typedef struct {
short diameter;
short numObjects;
windoid_object obj[100];
} wobj, ** wobjhdl;
/****************************************************************/
/******** Prototypes *********/
/****************************************************************/
void CreateWindoid(const XCmdPtr paramPtr);
void HandleEvent(const XCmdPtr paramPtr, const XWEventInfoPtr event);
void do_circle(const wobjhdl wobjh, const windoid_object what);
void do_activate(const XCmdPtr paramPtr, const WindowPtr wp, const short modifiers);
void do_update(const WindowPtr wp);
void do_click(const XCmdPtr paramPtr, const EventRecord * evnt, WindowPtr wp);
void do_key(const XCmdPtr paramPtr, const EventRecord * evnt, const WindowPtr wp);
void doCloseEvt(const XCmdPtr paramPtr, const XWEventInfoPtr evnt);
OSType GetFirstFourLwr(const StringPtr what);
void doSetPropEvt(const XCmdPtr paramPtr, const XWEventInfoPtr evnt);
void doGetPropEvt(const XCmdPtr paramPtr, const XWEventInfoPtr evnt);
void doCursorWithin(const XCmdPtr paramPtr, const XWEventInfoPtr evnt);
void do_content_click(const WindowPtr wp, Point where);
void do_mfevent(const XCmdPtr paramPtr, const WindowPtr wp, const long message);
void LocalToGlobalRect(const Rect * rectP);
Handle strToParam(const char * str);
/****************************************************************/
/******** Code *********/
/****************************************************************/
pascal void
main(const XCmdPtr paramPtr)
{
XWEventInfoPtr event;
paramPtr->returnValue = NIL;
paramPtr->passFlag = false;
/* If paramCount is less than zero, the first params entry is a pointer to a
* XWEventInfo record-Hypercard is passing us control to handle an event
* for a window we've created.
*/
if (paramPtr->paramCount < 0)
{
event = (XWEventInfoPtr)paramPtr->params[0];
HandleEvent(paramPtr,event);
}
/* Otherwise, the user has invoked the XCMD */
else if (paramPtr->paramCount >= 1)
{
/* Apple now recommends that all XCMDs and XFCNs support the following two
* commands: <name> ! and <name> ?, no matter how many parameters they
* normally get.
*/
if (paramPtr->paramCount == 1)
{
if (**(paramPtr->params[0]) == '!')
{
paramPtr->returnValue = strToParam(msgVersion);
return;
}
else if (**(paramPtr->params[0]) == '?')
{
paramPtr->returnValue = strToParam(msgUsage);
return;
}
}
/* This particular XCMD creates a window, with the user optionally specifying
* a few arguments.
*/
CreateWindoid(paramPtr);
}
else
paramPtr->returnValue = strToParam(msgUsage);
return;
}
/*
* Handle an event, either a system event or a Hypercard event.
*/
void
HandleEvent(const XCmdPtr paramPtr, const XWEventInfoPtr evnt)
{
WindowPtr wp;
GrafPtr savePort;
wp = evnt->eventWindow;
GetPort(&savePort);
SetPort(wp);
switch (evnt->event.what)
{
/* These are system events */
case mouseDown:
do_click(paramPtr, &evnt->event, wp);
break;
case keyDown:
case autoKey:
do_key(paramPtr, &evnt->event, wp);
break;
case updateEvt:
do_update(wp);
break;
case activateEvt:
do_activate(paramPtr, wp, evnt->event.modifiers);
break;
case nullEvent:
break;
case app4Evt:
do_mfevent(paramPtr, wp, evnt->event.message);
break;
/* These are Hypercard events */
case xOpenEvt:
/* Hypercard gives us this event just after it creates a window for us.
* We should do initialization stuff here that isn't done when we
* create the window
*/
break;
case xCloseEvt:
doCloseEvt(paramPtr, evnt);
break;
case xHidePalettesEvt:
case xShowPalettesEvt:
ShowHide(evnt->eventWindow, (evnt->event.what == xShowPalettesEvt));
break;
/* A user (or another XCMD) can send a message to one of our windows */
case xSendEvt:
break;
/* "get the … of window …" or set the … of window … to …" */
case xSetPropEvt:
doSetPropEvt(paramPtr, evnt);
break;
case xGetPropEvt:
doGetPropEvt(paramPtr, evnt);
break;
/* This is the Hypercard equivalent of a mouse-moved event */
case xCursorWithin:
doCursorWithin(paramPtr, evnt);
break;
/* Not playing a sound, so ignore this */
case xGiveUpSoundEvt:
break;
/* We never claim edit, so ignore these */
case xGiveUpEditEvt:
case xEditUndo:
case xEditCut:
case xEditCopy:
case xEditPaste:
case xEditClear:
break;
/* We have no menus, so ignore these */
case xMenuEvt:
case xMBarClickedEvt:
break;
/* We're not writing a debugger or script editor, so ignore these */
case xShowWatchInfoEvt:
case xScriptErrorEvt:
case xDebugErrorEvt:
case xDebugStepEvt:
case xDebugTraceEvt:
case xDebugFinishedEvt:
break;
}
SetPort(savePort);
return;
}
/*
* Create a simple window that will allow the user to draw circles,
* with some optional parameters possible
*/
void
CreateWindoid(const XCmdPtr paramPtr)
{
wobjhdl wobjh;
WindowPtr wp;
WindowPtr frontDoc;
Str255 title;
Byte boundsStr[64];
Rect bounds;
short paramCount;
short index = 0;
paramCount = paramPtr->paramCount;
/* The first argument is the window title */
if (--paramCount >= 0)
ZeroToPas(paramPtr, *paramPtr->params[index++], title);
else
BlockMove(strDefaultTitle, title, strlen(strDefaultTitle) + 1);
/* The second default argument is the bounding rectangle of the
* window, relative to the front document window, which is
* presumably the stack which called us.
*/
if (--paramCount >= 0)
{
ZeroToPas(paramPtr, *paramPtr->params[index++], boundsStr);
StrToRect(paramPtr, boundsStr, &bounds);
if (paramPtr->result != xresSucc)
SetRect(&bounds,20,20,270,270);
}
else
SetRect(&bounds,20,20,270,270);
frontDoc = FrontDocWindow(paramPtr);
SetPort(frontDoc);
LocalToGlobalRect(&bounds);
if (wp = NewXWindow(paramPtr,&bounds,title,true,noGrowDocProc,true,false))
{
wobjh = (wobjhdl)NewHandleClear(sizeof(wobj));
if (wobjh != NIL)
{
(*wobjh)->diameter = kDefaultDiameter;
(*wobjh)->numObjects = 0;
}
SetWRefCon(wp,(long)wobjh);
SelectWindow(wp);
}
}
/*
* These are the system event handling routines
*/
void
do_click(const XCmdPtr paramPtr, const EventRecord * evnt, WindowPtr wp)
{
GrafPtr wMgrPort;
wobjhdl wobjh;
short part;
switch (part = FindWindow(evnt->where,&wp))
{
case inContent:
wobjh = (wobjhdl) GetWRefCon(wp);
if (wobjh)
{
/* Register to receive keystrokes whenever the user clicks in
* our window. We're not doing a whole lot with them,
* but this is the place to register.
*/
BeginXWEdit(paramPtr, wp);
if (FrontDocWindow(paramPtr) != wp)
SelectWindow(wp);
else
do_content_click(wp, evnt->where);
}
break;
case inDrag:
/* We can't get the QD globals easily, look at the Window Manager port.
* This is equivalent to screenBits.bounds.
*/
GetWMgrPort(&wMgrPort);
DragWindow(wp,evnt->where,&wMgrPort->portRect);
break;
case inGoAway:
if (TrackGoAway(wp,evnt->where))
CloseXWindow(paramPtr,wp);
break;
default: /* inGrow, inZoomIn, inZoomOut */
break;
}
return;
}
void
do_content_click(const WindowPtr wp, Point where)
{
wobjhdl wobjh;
short i;
long color;
/* The port is already set */
GlobalToLocal(&where);
if (wobjh = (wobjhdl)GetWRefCon(wp))
{
if ((*wobjh)->numObjects < 100)
{
i = (Random() / 8192) + 4;
switch (i)
{
case 0:
case 1:
color = redColor;
break;
case 2:
color = greenColor;
break;
case 3:
color = blueColor;
break;
case 4:
color = cyanColor;
break;
case 5:
color = magentaColor;
break;
case 6:
color = yellowColor;
break;
case 7:
color = blackColor;
break;
}
(*wobjh)->obj[(*wobjh)->numObjects].center = where;
(*wobjh)->obj[(*wobjh)->numObjects].color = color;
do_circle(wobjh, (*wobjh)->obj[(*wobjh)->numObjects]);
(*wobjh)->numObjects++;
}
}
return;
}
void
do_key(const XCmdPtr paramPtr, const EventRecord * evnt, WindowPtr wp)
{
#pragma unused(paramPtr)
wobjhdl wobjh = (wobjhdl) GetWRefCon(wp);
long color;
Point where;
/* This is a fairly lame thing to do, but the begin and end edit stuff
* isn't entirely intuitive, so I put it in.
*/
if (wobjh && ((*wobjh)->numObjects < 100))
{
switch (evnt->message & charCodeMask)
{
case 'r':
case 'R':
color = redColor;
break;
case 'g':
case 'G':
color = greenColor;
break;
case 'b':
case 'B':
color = blueColor;
break;
case 'c':
case 'C':
color = cyanColor;
break;
case 'm':
case 'M':
color = magentaColor;
break;
case 'y':
case 'Y':
color = yellowColor;
break;
default:
SysBeep(1);
return;
}
/* Pick some random location, normalized between 0..max window size */
where.h = (Random() / (65536L / wp->portRect.right)) + (wp->portRect.right >> 1);
where.v = (Random() / (65536L / wp->portRect.bottom)) + (wp->portRect.bottom >> 1);
(*wobjh)->obj[(*wobjh)->numObjects].center = where;
(*wobjh)->obj[(*wobjh)->numObjects].color = color;
do_circle(wobjh, (*wobjh)->obj[(*wobjh)->numObjects]);
(*wobjh)->numObjects++;
}
return;
}
void
do_activate(const XCmdPtr paramPtr, const WindowPtr wp, const short modifiers)
{
/* Here's where we'd show or hide controls and call DrawGrowIcon */
if (modifiers & activeFlag)
BeginXWEdit(paramPtr, wp);
else
EndXWEdit(paramPtr, wp);
return;
}
void
do_mfevent(const XCmdPtr paramPtr, const WindowPtr wp, const long message)
{
#pragma unused(paramPtr)
if (((message&osEvtMessageMask) >> 24) == suspendResumeMessage)
do_activate(paramPtr, wp, (short)message);
return;
}
void
do_update(const WindowPtr wp)
{
wobjhdl wobjh;
short i;
/* Port is already set */
BeginUpdate(wp);
EraseRect(&wp->portRect);
if (wobjh = (wobjhdl)GetWRefCon(wp))
{
for (i = 0; i < (*wobjh)->numObjects; i++)
do_circle(wobjh, (*wobjh)->obj[i]);
}
EndUpdate(wp);
}
void
do_circle(const wobjhdl wobjh, const windoid_object what)
{
Rect bounds;
Point where = what.center;
short radius = (*wobjh)->diameter / 2;
/* Port is already set */
ForeColor(what.color);
SetRect(&bounds,where.h - radius, where.v - radius,
where.h + radius, where.v + radius);
PaintOval(&bounds);
ForeColor(blackColor);
return;
}
/*
* These are the routines to support Hypercard events.
*/
void
doCloseEvt(XCmdPtr paramPtr, XWEventInfoPtr evnt)
{
wobjhdl wobjh;
EndXWEdit(paramPtr, evnt->eventWindow);
if (wobjh = (wobjhdl)GetWRefCon(evnt->eventWindow))
DisposHandle((Handle)wobjh);
/* If we don't set passFlag to true, Hypercard gets all confused */
paramPtr->passFlag = true;
return;
}
void
doSetPropEvt(const XCmdPtr paramPtr, const XWEventInfoPtr evnt)
{
WindowPtr wp;
StringPtr property;
Str255 value;
long propCode;
long diameter;
Point newSize;
wobjhdl wobjh;
OSErr err = noErr;
Boolean passIt = false;
property = (StringPtr)evnt->eventParams[0]; /* pstring */
ReturnToPas(paramPtr,*(Handle)evnt->eventParams[1],value);
wp = evnt->eventWindow;
wobjh = (wobjhdl)GetWRefCon(wp);
propCode = GetFirstFourLwr(property);
if (property[0] >= 1 &&
StringMatch(paramPtr, property, supportedProperties) != NIL)
{
switch (propCode)
{
case 'diam':
diameter = StrToNum(paramPtr, value);
if (paramPtr->result != xresSucc || diameter <= 0)
{
err = 1;
paramPtr->returnValue = strToParam(msgBadDiameter);
break;
}
(*wobjh)->diameter = diameter;
InvalRect(&wp->portRect);
break;
case 'size':
StrToPoint(paramPtr, value, &newSize);
if (paramPtr->result != xresSucc ||
newSize.h <= 32 || newSize.v <= 32)
{
err = 1;
paramPtr->returnValue = strToParam(msgBadWindowSize);
break;
}
SizeWindow(wp, newSize.h, newSize.v, true);
break;
}
}
else /* Haven't a clue. Pass it on. */
passIt = true;
/* All done. Check err. If != noErr, complain */
if (err > 0) /* internal error */
paramPtr->result = xresFail;
paramPtr->passFlag = passIt; /* pass the event */
return;
}
void
doGetPropEvt(const XCmdPtr paramPtr, const XWEventInfoPtr evnt)
{
WindowPtr wp;
StringPtr property;
Str255 value;
long propCode;
Point curSize;
wobjhdl wobjh;
Boolean passIt = false;
property = (StringPtr)evnt->eventParams[0];
wp = evnt->eventWindow;
wobjh = (wobjhdl)GetWRefCon(wp);
/* return the value in the eventResult field */
propCode = GetFirstFourLwr(property);
evnt->eventResult = NIL;
propCode = GetFirstFourLwr(property);
if (property[0] >= 1 &&
StringMatch(paramPtr, property, supportedProperties) != NIL)
{
switch (propCode)
{
case 'diam':
NumToStr(paramPtr, (*wobjh)->diameter, value);
evnt->eventResult = PasToZero(paramPtr, value);
break;
case 'size':
curSize.h = wp->portRect.right - wp->portRect.left;
curSize.v = wp->portRect.bottom - wp->portRect.top;
PointToStr(paramPtr, curSize, value);
evnt->eventResult = PasToZero(paramPtr, value);
break;
case 'prop':
evnt->eventResult = strToParam(supportedProperties);
break;
default:
passIt = true;
break;
}
}
else /* Haven't a clue. Pass it on. */
passIt = true;
paramPtr->passFlag = passIt; /* pass the event */
return;
}
void
doCursorWithin(const XCmdPtr paramPtr, const XWEventInfoPtr evnt)
{
WindowPtr wp = evnt->eventWindow;
Point where;
CursHandle crossHair;
SignedByte state;
/* The port is set to our window */
GetMouse(&where);
if (PtInRgn(where, wp->visRgn))
{
if (crossHair = GetCursor(crossCursor))
{
state = HGetState((Handle)crossHair);
HLock((Handle)crossHair);
SetCursor(*crossHair);
HSetState((Handle)crossHair, state);
return; /* leave passFlag false */
}
}
paramPtr->passFlag = true; /* this sets cursor to arrow */
return;
}
/****************************************************************/
/******** Utils *********/
/****************************************************************/
void
LocalToGlobalRect(const Rect * rectP)
{
LocalToGlobal(&(((Point *) rectP)[0]));
LocalToGlobal(&(((Point *) rectP)[1]));
return;
}
Handle
strToParam(const char * str)
{
Handle out = NIL;
long len;
if ((len = strlen(str)) && (out = NewHandle(len + 1)))
BlockMove(str, *out, len + 1);
return(out);
}
OSType
GetFirstFourLwr(const StringPtr what)
{
long firstfour;
firstfour = ' '; /* four spaces */
BlockMove(&what[1],(Ptr)&firstfour,(what[0] < 4) ? what[0] : 4);
LwrText((Ptr)&firstfour,4);
return(firstfour);
}
/*******
* end *
*******/